from django.shortcuts import render, get_object_or_404 , redirect
from django.http import HttpResponse,HttpResponseNotFound
from django.utils import timezone
import paramiko , time , telnetlib , datetime
from .models import device_information , Log
from .asyncio_socket import *

def FishingRod(request):
    if request.method == 'GET':
        return render(request,'FishingRod.html')

def homepage(request):
    if request.method == 'GET':
        All_devices = device_information.objects.all()
        num_event = len(Log.objects.all())
        if num_event != 0:
            if num_event >= 10:
                last_10_event = Log.objects.all()[num_event-10:num_event]
            else:
                last_10_event = Log.objects.all()[0:10]
        else:
            last_10_event = []
        Cisco_devices = device_information.objects.filter(vendor='cisco')
        Huawei_devices = device_information.objects.filter(vendor='huawei')
        last_10_event = list(last_10_event)
        last_10_event.reverse()
        Devices_context = {
            'All_devices' : len(All_devices),
            # 'Cisco_devices' : Cisco_devices,
            # 'Huawei_devices' : Huawei_devices,
            'Cisco_num' : len(Cisco_devices),
            'Huawei_num' : len(Huawei_devices),
            'last_10_event' : last_10_event,
        }
        return render(request,'homepage.html',Devices_context)

def console(request):
    if request.method == 'GET':
        Devices = device_information.objects.all()
        return render(request,'console.html',{'Devices':Devices})
    elif request.method == 'POST':
        result = []
        connection_method = request.POST.get('btnradio') #连接方式
        connect_device = request.POST.get('exampleRadios') #连接设备
        command_line = request.POST['command'].splitlines() #命令行
        dev_info = get_object_or_404(device_information,pk=connect_device) #在数据表中提取相应id的数据
        if connection_method == 'SSH':
            try:
                ssh_client = paramiko.SSHClient() #开启paramiko建立shh会话的函数
                ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) #默认情况下paramiko会拒绝任何位置的ssh公匙，使用此命令添加信任远程机器
                # 如果用paramiko第一次登陆一台交换机，我们会接收到对方发送的一个公匙。如果不配置则shh会连接失败
                ssh_client.connect(hostname=dev_info.ip_address,username=dev_info.username,
                                   password=dev_info.password,look_for_keys=False)
                # 连接。look_for_keys默认为True，会在建立连接之前查看本地是否有目标主机的私匙，没有会连接失败
                # time.sleep(1)
                conso = ssh_client.invoke_shell()
                for c in command_line:
                    conso.send(c + '\n')
                    time.sleep(1)
                    output = conso.recv(65535).decode('ascii')
                    result.append(output)
                log = Log(target=dev_info.ip_address,action='SSH connect',status='Success',time=datetime.datetime.now(),message='')
            except Exception as e:
                result = dev_info.ip_address+'SSH连接失败，原因：\n'+str(e)
                log = Log(target=dev_info.ip_address,action='SSH connect',status='Error',time=datetime.datetime.now(),message=e)
            log.save()
            if '失败' not in result:
                result = '\n'.join(result)
        elif connection_method == 'Telnet':
            try:
                tel = telnetlib.Telnet(dev_info.ip_address)
                tel.read_until(b"Username: ")
                tel.write(dev_info.username.encode('ascii') + b"\n")
                tel.read_until(b"Password: ")
                tel.write(dev_info.password.encode('ascii') + b"\n")

                for c in command_line:
                    tel.write(f"{c}" + b"\n")
                    time.sleep(1)
                tel.write(b"end\n")
                tel.write(b"exit\n")
                result = tel.read_all().decode('ascii')
                log = Log(target=dev_info.ip_address,action='Telnet connect',status='Success',time=datetime.datetime.now(),message='No Error')
            except Exception as e:
                result = dev_info.ip_address+'Telnet连接失败，原因：\n'+str(e)
                log = Log(target=dev_info.ip_address,action='Telnet connect',status='Error',time=datetime.datetime.now(),message=e)
            log.save()
        content = {
            'result' : result ,
            'info' : dev_info,
            'method' : connection_method,
        }
        return render(request , 'show.html' , content)

def re_console(request):
    if request.method == 'GET':
        return HttpResponse('get')
    elif request.method == 'POST':
        result = []
        info_method = request.POST.get('Re_post')
        id = info_method[0]
        connection_method = info_method.split('+')[-1]
        dev_info = device_information.objects.filter(pk=id)[0]
        command_line = request.POST['command'].splitlines() #命令行
        if connection_method == 'SSH':
            try:
                ssh_client = paramiko.SSHClient() #开启paramiko建立shh会话的函数
                ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) #默认情况下paramiko会拒绝任何位置的ssh公匙，使用此命令添加信任远程机器
                # 如果用paramiko第一次登陆一台交换机，我们会接收到对方发送的一个公匙。如果不配置则shh会连接失败
                ssh_client.connect(hostname=dev_info.ip_address,username=dev_info.username,
                                   password=dev_info.password,look_for_keys=False)
                # 连接。look_for_keys默认为True，会在建立连接之前查看本地是否有目标主机的私匙，没有会连接失败
                # time.sleep(1)
                conso = ssh_client.invoke_shell()
                for c in command_line:
                    conso.send(c + '\n')
                    time.sleep(1)
                    output = conso.recv(65535).decode('ascii')
                    result.append(output)
                log = Log(target=dev_info.ip_address,action='SSH connect',status='Success',time=datetime.datetime.now(),message='')
            except Exception as e:
                result = dev_info.ip_address+'SSH连接失败，原因：\n'+str(e)
                log = Log(target=dev_info.ip_address,action='SSH connect',status='Error',time=datetime.datetime.now(),message=e)
            log.save()
            if '失败' not in result:
                result = '\n'.join(result)
        elif connection_method == 'Telnet':
            try:
                tel = telnetlib.Telnet(dev_info.ip_address)
                tel.read_until(b"Username: ")
                tel.write(dev_info.username.encode('ascii') + b"\n")
                tel.read_until(b"Password: ")
                tel.write(dev_info.password.encode('ascii') + b"\n")

                for c in command_line:
                    tel.write(f"{c}" + b"\n")
                    time.sleep(1)
                tel.write(b"end\n")
                tel.write(b"exit\n")
                result = tel.read_all().decode('ascii')
                log = Log(target=dev_info.ip_address,action='Telnet connect',status='Success',time=datetime.datetime.now(),message='No Error')
            except Exception as e:
                result = dev_info.ip_address+'Telnet连接失败，原因：\n'+str(e)
                log = Log(target=dev_info.ip_address,action='Telnet connect',status='Error',time=datetime.datetime.now(),message=e)
            log.save()
        content = {
            'result' : result ,
            'info' : dev_info,
            'method' : connection_method,
        }
        return render(request , 'show.html' , content)

def devices_list(request):
    if request.method == 'GET':
        Devices = device_information.objects.all()
        return render(request,'device_list.html',{'Devices':Devices})
    elif request.method == 'POST':
        if request.POST.get('id') == 'Post_info':
            # return HttpResponse(request.POST["id"])
            ip = request.POST['ip']
            username = request.POST['username']
            hostname = request.POST['hostname']
            pwd = request.POST['pwd']
            port = request.POST['port']
            vendor = request.POST['vendor']

            post_bool = True
            for i in ip,username,hostname,pwd,port,vendor:
                if i == '':
                    post_bool = False

            if post_bool:
                try:
                    device_information.objects.create(ip_address=ip,
                                    username=username,
                                    hostname=hostname,
                                    password=pwd,
                                    port=port,
                                    vendor=vendor)
                    log = Log(target=ip,action='info submit',status='Success',time=datetime.datetime.now(),message='No Error')
                except Exception as e:
                    log = Log(target=ip, action='info submit', status='Error', time=datetime.datetime.now(),message=e)
                log.save()
                return redirect('/dev_list')
            # elif post_bool == False:
            #     Log(target=ip, action='front end submit', status='error', time=datetime.datetime.now(),message='Null submit')
        else:
            delete_ip = device_information.objects.filter(pk=request.POST["id"])[0].ip_address
            try:
                device_information.objects.filter(pk=request.POST["id"]).delete() #数据表中删除前端提交的指定id
                log = Log(target=delete_ip,action='info delete',status='Success',time=datetime.datetime.now(),message='No Error')
            except Exception as e:
                log = Log(target=delete_ip,action='info delete',status='Error',time=datetime.datetime.now(),message=e)
            log.save()
            return redirect('/dev_list')

def device_detail(request,id):
    if request.method == 'GET':
        try:
            device_info = device_information.objects.get(id=id) #读取该数据表中第id号数据
            other_vendor = []
            [other_vendor.append(i[0]) for i in device_information.VENDOR_CHOICES if i[0] != device_info.vendor]
            my_vendor = [i[0] for i in device_information.VENDOR_CHOICES if i[0] == device_info.vendor][0]

            content = {
                "device_info" : device_info,
                "my_vendor" : my_vendor,
                "other_vendor" : other_vendor,
            }
            return render(request,"device_detail.html",content) #返回给html相应数值
        except device_information.DoesNotExist:
            return HttpResponseNotFound()
    elif request.method == 'POST':
        try:
            device_info = device_information.objects.get(id=id) #读取该数据表中第id号数据
            device_info.ip_address = request.POST['ip']
            device_info.username = request.POST['username']
            device_info.hostname = request.POST['hostname']
            device_info.pwd = request.POST['pwd']
            device_info.port = request.POST['port']
            device_info.vendor = request.POST['vendor']
            device_info.save()
            # device_info.objects.update(ip_address=ip,username=username,hostname=hostname,password=pwd,port=port,vendor=vendor)
            # login_at=datetime.datetime.now(tz=timezone.utc)) #update方法失效，待深究
            log = Log(target=device_info.ip_address, action='detail modify', status='Success', time=datetime.datetime.now(), message='No Error')
        except Exception as e:
            log = Log(target=device_info.ip_address, action='detail modify', status='Error', time=datetime.datetime.now(), message=e)
        log.save()
        return redirect('/dev_list')

def Port_scan(request):
    if request.method == 'GET': #主页面
        # asyncio.run(socket_main())
        Devices = device_information.objects.all()
        content = {
            'port' : '22,23',
            'Devices' : Devices,
        }
        return render(request,'port_scan.html',content)
    elif request.method == 'POST': #主页面提交表单处理
        ip_pool = request.POST.getlist('pick')
        port = request.POST.get('port')
        Original_port = port
        Original_ip = ip_pool
        #get多个name属性为pick的value值
        # return HttpResponse(request.POST.get('choice'))
        # return HttpResponse(request.POST.get('all_choice'))
        if request.POST.get('choice') == 'multiple_choice' and ip_pool == [] or port == '': #空选
            return redirect('/scan')
        elif request.POST.get('ip'): #重新扫描
            ip_pool = request.POST.get('ip')
            if ',' in ip_pool: #多选重扫
                # return HttpResponse(request.POST.get('Original_port'))
                port = request.POST.get('Original_port')
                ip_pool = request.POST.get('Original_ip')
                port = port.replace('，',',').replace(' ','')
                port = port.split(',')
                port_list = [i for i in port if i != '']
                ip_pool = ip_pool.split(',')
                all_info = [ip_pool,port_list]
                result = asyncio.run(socket_main(all_info))
                content = {
                    'ip': request.POST.get('ip'),
                    'result': result
                }
                log = Log(target=request.POST.get('ip'), action='Port Rescan', status='Success', time=datetime.datetime.now(), message='No Error')
                log.save()
                return render(request,'pick_scan.html',content)
            elif request.POST.get('ip') == '全局': #全局重扫
                # return HttpResponse(request.POST.get('ip'))
                Device = device_information.objects.all()
                port = request.POST.get('Original_port')
                port = port.replace('，',',').replace(' ','')
                port = port.split(',')
                port_list = [i for i in port if i != '']
                ip_pool = []
                for dev in Device:
                    ip_pool.append(dev.ip_address)
                all_info = [ip_pool,port_list]
                # return HttpResponse(all_info)
                result = asyncio.run(socket_main(all_info))
                content = {
                    'ip' : '全局',
                    'result' : result
                }
                log = Log(target='Global address', action='Port Rescan', status='Success', time=datetime.datetime.now(), message='No Error')
                log.save()
                return render(request,'pick_scan.html',content)
            else: #单选重扫
                # return HttpResponse(request.POST.get('ip'))
                port = request.POST.get('Original_port')
                ip_pool = request.POST.get('Original_ip')
                port = port.replace('，',',').replace(' ','')
                port = port.split(',')
                port_list = [i for i in port if i != '']
                # return HttpResponse([ip_pool]+port_list)
                all_info = [[ip_pool],port_list]
                result = asyncio.run(socket_main(all_info))
                content = {
                    'ip': ip_pool,
                    'result': result
                }
                log = Log(target=ip_pool, action='Port Rescan', status='Success', time=datetime.datetime.now(), message='No Error')
                log.save()
                return render(request,'pick_scan.html',content)
        elif request.POST.get('choice') != 'multiple_choice' and request.POST.get('all_choice') != 'All': #单选
            # return HttpResponse(request.POST.get('choice'))
            port = port.replace('，',',').replace(' ','')
            port = port.split(',')
            port_list = [i for i in port if i != '']
            ip = request.POST.get('choice')
            all_info = [[ip],port_list]
            # return HttpResponse(all_info)
            result = asyncio.run(socket_main(all_info))
            # return HttpResponse(result)
            content = {
                'ip' : ip,
                'port' : Original_port,
                'result' : result
            }
            log = Log(target=ip_pool, action='Port Scan', status='Success', time=datetime.datetime.now(), message='No Error')
            log.save()
            return render(request,'pick_scan.html',content)
        elif request.POST.get('choice') == 'multiple_choice': #多选
            port = port.replace('，',',').replace(' ','')
            port = port.split(',')
            port_list = [i for i in port if i != '']
            ip = str(ip_pool).replace('[','').replace(']','').replace("'",'').replace(' ','')
            all_info = [ip_pool,port_list]
            result = asyncio.run(socket_main(all_info))
            # return HttpResponse(result)
            content = {
                'ip' : ip,
                'port' : Original_port,
                'result' : result
            }
            log = Log(target=ip, action='Port Scan', status='Success', time=datetime.datetime.now(), message='No Error')
            log.save()
            return render(request,'pick_scan.html',content)
        elif request.POST.get('all_choice') == 'All': #全局
            # return HttpResponse(request.POST.get('all_choice'))
            Device = device_information.objects.all()
            port = port.replace('，',',').replace(' ','')
            port = port.split(',')
            port_list = [i for i in port if i != '']
            ip_pool = []
            for dev in Device:
                ip_pool.append(dev.ip_address)
            all_info = [ip_pool,port_list]
            result = asyncio.run(socket_main(all_info))
            content = {
                'ip' : '全局',
                'port' : Original_port,
                'result' : result
            }
            log = Log(target='Global address', action='Port Scan', status='Success', time=datetime.datetime.now(), message='No Error')
            log.save()
            return render(request,'pick_scan.html',content)
        else:
            # return HttpResponse(request.POST.get('choice'))
            return HttpResponse(request.POST.get('all_choice'))

def Pick_scan(request,id): #原单选href跳转，已弃
    if request.method == 'GET':
        info = device_information.objects.filter(pk=id)[0]
        # filter方法返回的是一个QuerySet类集合，所以要以列表方法处理filter筛选结果
        # 与get方法不同，get方法返回的是一个数据表集数据，所以可以直接指定数据
        all_info = [[info.ip_address],['22','23']]
        result = asyncio.run(socket_main(all_info))
        content = {
            'scan_info' : info,
            'result' : result
        }
        log = Log(target=info.ip_address, action='Port Scan', status='Success', time=datetime.datetime.now(), message='No Error')
        log.save()
        return render(request,'pick_scan.html',content)
    elif request.method == 'POST':
        id=str(id)
        if len(id) == 1:
            url = '/scan/'+id
            info = device_information.objects.filter(pk=id)[0]
            log = Log(target=info.ip_address, action='Port Rescan', status='Success', time=datetime.datetime.now(), message='No Error')
            log.save()
            return redirect(url)

def All_scan(request): #原全局跳转，已弃
    if request.method == 'GET':
        Device = device_information.objects.all()
        ip_pool = []
        for dev in Device:
            ip_pool.append(dev.ip_address)
        port = request.POST.get('port')
        result = asyncio.run(socket_main([ip_pool,['22','23']]))
        content = {
            'ip' : '全局',
            'result' : result
        }
        log = Log(target='Global address', action='Port Scan', status='Success', time=datetime.datetime.now(), message='No Error')
        log.save()
        return render(request,'all_scan.html',content)
    elif request.method == 'POST':
        log = Log(target='Global address', action='Port Rescan', status='Success', time=datetime.datetime.now(), message='No Error')
        log.save()
        return redirect('/scan/all')

def log(request):
    if request.method == 'GET':
        logs_ascending = Log.objects.all()
        logs_reverse = list(logs_ascending)
        logs_reverse.reverse()
        context = {'logs' : logs_reverse,
                   }
        return render(request, 'log.html', context)
    elif request.method == 'POST':
        pass

def test(request): #测试用
    if request.method == 'GET':
        Devices = device_information.objects.all()
        return render(request,'test.html',{'Devices':Devices})
    elif request.method == 'POST':
        a = request.POST["ip_address"]
        return HttpResponse(a)

def move(request):
    if request.method == 'GET':
        return render(request,'move.html')
